fscanf in C/C++: reading from a file
Hey there! In this article, we’ll be diving into the fscanf
function. This function is pretty similar to scanf
, but instead of reading values from standard input, it reads them from a file. We’ll kick things off with an overview using examples and then delve into the format specifiers this function supports (which are the same as scanf
, so if you’re familiar with it, you will find them familiar). At the end, there are some exercises for further practice.
How to read values from a file using fscanf
To read values from a file, you can make use of the fscanf
function. This function is declared in the header file <stdio.h>
. In C++, you can include <cstdio>
. The function looks like this:
int fscanf ( FILE * stream, const char * format, ... );
- The first argument should be a pointer to the file from which you want to read.
- The second argument is the format string which dictates how the file should be read.
- Then, you pass as many arguments as
fscanf
expects based on the format string. - The function returns the number of values it read from the file. If everything goes well, this number should be equal to the number of arguments following the format string.
Let’s look at a few examples:
#include <stdio.h>
int main() {
FILE * f = fopen("input.txt", "r");
int x;
int n = fscanf(f, "x: %d", &x);
fclose(f);
printf("x = %d, n = %d", x, n);
return 0;
}
input.txt:
x: 4
Program output:
x = 4, n = 1
In the program above, we read an int
variable from a file using the format specifier %d
(more on specifiers shortly). After reading, we printed out x
and the number of arguments read.
Now, let’s try reading something a bit more complex:
#include <stdio.h>
int main() {
FILE* f = fopen("input.txt", "r");
unsigned int x;
char s[100];
float pi;
int n = fscanf(f, "hex: %x, s = %s\nfloat <- %f", &x, s, &pi);
fclose(f);
printf("x = %d, s = %s, pi = %f, n = %d", x, s, pi, n);
return 0;
}
input.txt:
hex: 0xABC, s = fscanf
float <- 3.14
Program output:
x = 2748, s = fscanf, pi = 3.140000, n = 3
As you can see, fscanf
managed the complex format just fine. Let’s now “mess up” the input.txt file so that fscanf
can only read the first two values:
hex: 0xABC, s = fscanf
UNKNOWN <- 3.14
With the start of the second line altered, let’s run the program again and see the output:
x = 2748, s = fscanf, pi = 0.000000, n = 2
Everything here is as expected:
fscanf
could read the first two values since they remained unchanged.- However, when reading the second line of the file,
fscanf
hits the unexpected ‘U’ character and stops reading. - Ultimately, we see that only two values were read (
n
equals two).pi
remains with its default value (in this case, zero).
What will be displayed on the screen?
#include <stdio.h>
int main() {
FILE* f = fopen("data.txt", "r");
char word[50];
double number;
int n = fscanf(f, "%s = %lf", word, &number);
fclose(f);
printf("word = %s, number = %lf, n = %d", word, number, n);
return 0;
}
data.txt:
result = 42.58
Now, let’s have a look at all the possible format specifiers you can use with the fscanf
function.
Format specifiers
The structure of the specifier in fscanf
differs slightly from the one in fprintf
. Here’s a look (optional modifiers are in square brackets):
%[*][width][length]type
From this, only the percentage sign and type are mandatory; you can skip the rest. These specifiers are pretty much the same as the ones in scanf
(yeah, the one that reads from standard input, not a file).
Types
Type | Description | Example | File |
---|---|---|---|
i | Reads an integer in octal, decimal, or hexadecimal. |
|
|
d | Reads a decimal integer. |
|
|
u | Reads a positive decimal integer. |
|
|
o | Reads an octal integer. |
|
|
x | Reads a hexadecimal integer. |
|
|
f , e , g , a | Reads a floating-point number. |
|
|
c | Reads a character. |
|
|
s | Reads a string until the first whitespace. |
|
|
p | Reads a memory address. |
|
|
[characters] | Reads a string until it finds a character that isn’t among those inside the brackets. |
|
|
[^characters] | Reads a string until it encounters a character that matches one from inside the brackets, after the |
|
|
n | Doesn’t read anything. Writes the number of characters read up to this point. |
|
|
%% | Reads the percentage sign. |
|
|
Ignoring input
You can add an asterisk right after the percentage sign if you’re like, “I don’t wanna save this value”:
FILE * f = fopen("input.txt", "r");
int x;
fscanf(f, "Skip: %*d, save: %d", &x);
printf("Number: %d", x);
input.txt:
Skip: 123, save: 456
Output:
Number: 456
You can slap that asterisk on any type from the table above, not just numbers.
Width
We can define the maximum number of characters to be read by the fscanf
function:
FILE * f = fopen("input.txt", "r");
char s[4]; // 3 characters + '\0'
fscanf(f, "%3s", s);
printf("Read: %s", s);
input.txt:
C++11
Output:
Read: C++
Just like the asterisk, you can specify a width for any type.
Length
By default, fscanf
reads values of type int
, unsigned int
, float
, and char
(depending on the specifier type). To read, say, a value into a long long int
variable, we need to explicitly state the length:
#include <math.h>
#include <stdio.h>
int main() {
FILE * f = fopen("input.txt", "r");
long long int x;
printf("Number: ");
fscanf(f, "%lld", &x);
// ^ added ll for long long int
printf("Read: %lld\n", x);
// ^ don't forget this in printf either
return 0;
}
input.txt:
Number: 10000000000
Output:
Read: 10000000000
Without specifying the size, the output might look something like this:
Read: 5705032704
This odd output is because ten billion just doesn’t fit into the int
type, which fscanf
tries to read without a specified size.
Here’s a quick size chart for you:
Size | Type |
---|---|
hh |
|
h |
|
l |
|
ll |
|
j |
|
z |
|
t |
|
L |
|
Exercises
- Reading various data types:
Write a C++ program that usesfscanf
to read different data types from a file. The file should have an integer, a float, and a string. After reading, the program should display these values. - Handling read errors:
Modify your data file so one of the lines doesn’t match the format you’re expecting. Then tweak your program to handle this gracefully, like maybe by printing an error message. - Using different format specifiers:
Write a program showcasing the use of different format specifiers withfscanf
. Set up a file with various data (like integers, floats, strings, hex numbers) and pull them from the file, displaying the results.
Discussion